home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / access / heap / heapam.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  43.5 KB  |  1,733 lines

  1. /* ----------------------------------------------------------------
  2.  *   FILE
  3.  *    heapam.c
  4.  *    
  5.  *   DESCRIPTION
  6.  *    heap access method code
  7.  *
  8.  *   INTERFACE ROUTINES
  9.  *    heapgettup     - fetch next heap tuple from a scan
  10.  *    heap_open     - open a heap relation by relationId
  11.  *    heap_openr     - open a heap relation by name
  12.  *    heap_close     - close a heap relation
  13.  *    heap_beginscan    - begin relation scan
  14.  *    heap_rescan    - restart a relation scan
  15.  *    heap_endscan    - end relation scan
  16.  *    heap_getnext    - retrieve next tuple in scan
  17.  *    heap_fetch    - retrive tuple with tid
  18.  *    heap_insert    - insert tuple into a relation
  19.  *    heap_delete    - delete a tuple from a relation
  20.  *    heap_replace    - replace a tuple in a relation with another tuple
  21.  *    heap_markpos    - mark scan position
  22.  *    heap_restrpos    - restore position to marked location
  23.  *    
  24.  *   NOTES
  25.  *    This file contains the heap_ routines which implement
  26.  *    the POSTGRES heap access method used for all POSTGRES
  27.  *    relations.  
  28.  *
  29.  *  old comments:
  30.  *    struct relscan hints:  (struct should be made AM independent?)
  31.  *
  32.  *    rs_ctid is the tid of the last tuple returned by getnext.
  33.  *    rs_ptid and rs_ntid are the tids of the previous and next tuples
  34.  *    returned by getnext, respectively.  NULL indicates an end of
  35.  *    scan (either direction); NON indicates an unknow value.
  36.  *
  37.  *    possible combinations:
  38.  *    rs_p    rs_c    rs_n        interpretation
  39.  *    NULL    NULL    NULL        empty scan
  40.  *    NULL    NULL    NON        at begining of scan
  41.  *    NULL    NULL    t1        at begining of scan (with cached tid)
  42.  *    NON    NULL    NULL        at end of scan
  43.  *    t1    NULL    NULL        at end of scan (with cached tid)
  44.  *    NULL    t1    NULL        just returned only tuple
  45.  *    NULL    t1    NON        just returned first tuple
  46.  *    NULL    t1    t2        returned first tuple (with cached tid)
  47.  *    NON    t1    NULL        just returned last tuple
  48.  *    t2    t1    NULL        returned last tuple (with cached tid)
  49.  *    t1    t2    NON        in the middle of a forward scan
  50.  *    NON    t2    t1        in the middle of a reverse scan
  51.  *    ti    tj    tk        in the middle of a scan (w cached tid)
  52.  *
  53.  *    Here NULL is ...tup == NULL && ...buf == InvalidBuffer,
  54.  *    and NON is ...tup == NULL && ...buf == UnknownBuffer.
  55.  *
  56.  *    Currently, the NONTID values are not cached with their actual
  57.  *    values by getnext.  Values may be cached by markpos since it stores
  58.  *    all three tids.
  59.  *
  60.  *    NOTE:  the calls to elog() must stop.  Should decide on an interface
  61.  *    between the general and specific AM calls.
  62.  *
  63.  *     XXX probably do not need a free tuple routine for heaps.
  64.  *     Huh?  Free tuple is not necessary for tuples returned by scans, but
  65.  *     is necessary for tuples which are returned by
  66.  *    RelationGetTupleByItemPointer. -hirohama
  67.  *
  68.  *   IDENTIFICATION
  69.  *    $Header: /private/postgres/src/access/heap/RCS/heapam.c,v 1.49 1992/08/24 23:14:44 mao Exp $
  70.  * ----------------------------------------------------------------
  71.  */
  72.  
  73.  
  74. #include <sys/file.h>
  75. #include <strings.h>
  76.  
  77. #include "tmp/postgres.h"
  78.  
  79. RcsId("$Header: /private/postgres/src/access/heap/RCS/heapam.c,v 1.49 1992/08/24 23:14:44 mao Exp $");
  80.  
  81. #include "access/att.h"
  82. #include "access/attnum.h"
  83. #include "access/heapam.h"
  84. #include "access/hio.h"
  85. #include "access/hrnd.h"
  86. #include "access/htup.h"
  87. #include "access/relscan.h"
  88. #include "access/skey.h"
  89.  
  90. #include "access/tqual.h"
  91. #include "access/valid.h"
  92. #include "access/xcxt.h"
  93. #include "access/xact.h"
  94.  
  95. #include "catalog/catname.h"
  96. #include "rules/rac.h"
  97. #include "rules/rlock.h"
  98.  
  99. #include "storage/buf.h"
  100. #include "storage/bufmgr.h"
  101. #include "storage/bufpage.h"
  102. #include "storage/itemid.h"
  103. #include "storage/itemptr.h"
  104. #include "storage/page.h"
  105. #include "storage/lmgr.h"
  106.  
  107. #include "tcop/slaves.h"
  108. #include "tcop/tcopdebug.h"
  109. #include "tmp/miscadmin.h"
  110.  
  111. #include "utils/memutils.h"
  112. #include "utils/fmgr.h"
  113. #include "utils/inval.h"
  114. #include "utils/log.h"
  115. #include "utils/mcxt.h"
  116. #include "utils/rel.h"
  117. #include "utils/relcache.h"
  118.  
  119. /* If RANDOMINSERT is defined, random pages will be examined to see if there
  120.  * is space for insertion.  If it is not defined, the new tuple is always
  121.  * appended to the end.
  122.  * plai 8/7/90
  123.  */
  124. #undef RANDOMINSERT
  125.  
  126. static bool    ImmediateInvalidation;
  127. extern HeapAccessStatistics heap_access_stats;
  128.  
  129. /* ----------------------------------------------------------------
  130.  *                       heap support routines
  131.  * ----------------------------------------------------------------
  132.  */
  133.  
  134. /* ----------------
  135.  *    initsdesc - sdesc code common to heap_beginscan and heap_rescan
  136.  * ----------------
  137.  */
  138. void
  139. initsdesc(sdesc, relation, atend, nkeys, key)
  140.     HeapScanDesc sdesc;
  141.     Relation     relation;
  142.     int         atend;
  143.     unsigned     nkeys;
  144.     ScanKey     key;
  145. {
  146.     if (!RelationGetNumberOfBlocks(relation)) {
  147.     /* ----------------
  148.      *  relation is empty
  149.      * ----------------
  150.      */
  151.     sdesc->rs_ntup = sdesc->rs_ctup = sdesc->rs_ptup = NULL;
  152.     sdesc->rs_nbuf = sdesc->rs_cbuf = sdesc->rs_pbuf = InvalidBuffer;
  153.     } else if (atend) {
  154.     /* ----------------
  155.      *  reverse scan
  156.      * ----------------
  157.      */
  158.     sdesc->rs_ntup = sdesc->rs_ctup = NULL;
  159.     sdesc->rs_nbuf = sdesc->rs_cbuf = InvalidBuffer;
  160.     sdesc->rs_ptup = NULL;
  161.     sdesc->rs_pbuf = UnknownBuffer;
  162.     } else {
  163.     /* ----------------
  164.      *  forward scan
  165.      * ----------------
  166.      */
  167.     sdesc->rs_ctup = sdesc->rs_ptup = NULL;
  168.     sdesc->rs_cbuf = sdesc->rs_pbuf = InvalidBuffer;
  169.     sdesc->rs_ntup = NULL;
  170.     sdesc->rs_nbuf = UnknownBuffer;
  171.     } /* invalid too */
  172.  
  173.     /* we don't have a marked position... */
  174.     ItemPointerSetInvalid(&(sdesc->rs_mptid));
  175.     ItemPointerSetInvalid(&(sdesc->rs_mctid));
  176.     ItemPointerSetInvalid(&(sdesc->rs_mntid));
  177.     ItemPointerSetInvalid(&(sdesc->rs_mcd));
  178.  
  179.     /* ----------------
  180.      *    copy the scan key, if appropriate
  181.      * ----------------
  182.      */
  183.     if (key != NULL)
  184.     bcopy((char *)&key->data[0],
  185.           (char *)&sdesc->rs_key.data[0],
  186.           (int)nkeys * sizeof *key);
  187. }
  188.  
  189. /* ----------------
  190.  *    unpinsdesc - code common to heap_rescan and heap_endscan
  191.  * ----------------
  192.  */
  193. void
  194. unpinsdesc(sdesc)
  195.     HeapScanDesc    sdesc;
  196. {
  197.     if (BufferIsValid(sdesc->rs_pbuf)) {
  198.     ReleaseBuffer(sdesc->rs_pbuf);
  199.     }
  200.  
  201.     /* ------------------------------------
  202.      *  each scan will only pin a buffer once, so make sure not to
  203.      *  unpin them multiple times.
  204.      * ------------------------------------
  205.      */
  206.     if (sdesc->rs_cbuf != sdesc->rs_pbuf && BufferIsValid(sdesc->rs_cbuf)) {
  207.     ReleaseBuffer(sdesc->rs_cbuf);
  208.     }
  209.  
  210.     if (sdesc->rs_nbuf != sdesc->rs_cbuf &&
  211.     sdesc->rs_nbuf != sdesc->rs_pbuf &&
  212.     BufferIsValid(sdesc->rs_nbuf)) {
  213.        ReleaseBuffer(sdesc->rs_nbuf);
  214.     }
  215. }
  216.  
  217. #define initskip(PARALLEL_OK)    ((ParallelExecutorEnabled() && PARALLEL_OK)? \
  218.                  SlaveLocalInfoD.startpage:0)
  219.  
  220. /* ------------------------------------------
  221.  *    nextpage
  222.  *
  223.  *    figure out the next page to scan after the current page
  224.  *    taking into account of possible adjustment of degrees of
  225.  *    parallelism
  226.  * ------------------------------------------
  227.  */
  228. int
  229. nextpage(page, dir, parallel_ok)
  230. int page;
  231. int dir;
  232. bool parallel_ok;
  233. {
  234.     int skip;
  235.     int nextpage;
  236.  
  237.     if (!ParallelExecutorEnabled() || !parallel_ok)
  238.     return((dir<0)?page-1:page+1);
  239.     nextpage = paradj_nextpage(page, dir);
  240.     if (nextpage == NULLPAGE) {
  241.         skip = SlaveLocalInfoD.nparallel;
  242.         nextpage = (dir<0)?page-skip:page+skip;
  243.       }
  244.     return nextpage;
  245. }
  246.  
  247. /* ----------------
  248.  *    heapgettup - fetch next heap tuple
  249.  *
  250.  *    routine used by heap_getnext() which does most of the
  251.  *    real work in scanning tuples.
  252.  * ----------------
  253.  */
  254. static
  255. HeapTuple
  256. heapgettup(relation, tid, dir, b, timeQual, nkeys, key, parallel_ok)
  257.     Relation        relation;
  258.     ItemPointer        tid;
  259.     int            dir;
  260.     Buffer        *b;
  261.     TimeQual        timeQual;
  262.     ScanKeySize        nkeys;
  263.     ScanKey        key;
  264.     bool        parallel_ok;
  265. {
  266.     ItemId        lpp;
  267.     Page        dp;
  268.     int            page;
  269.     int            lineoff;
  270.     int            pages;
  271.     int            lines;
  272.     HeapTuple        rtup;
  273.     OffsetIndex        offsetIndex;
  274.  
  275.     /* ----------------
  276.      *    increment access statistics
  277.      * ----------------
  278.      */
  279.     IncrHeapAccessStat(local_heapgettup);
  280.     IncrHeapAccessStat(global_heapgettup);
  281.     
  282.     /* ----------------
  283.      *    debugging stuff 
  284.      *
  285.      * check validity of arguments, here and for other functions too
  286.      * Note: no locking manipulations needed--this is a local function
  287.      * ----------------
  288.      */
  289. #ifdef    HEAPDEBUGALL
  290.     if (ItemPointerIsValid(tid)) {
  291.         elog(DEBUG, "heapgettup(%.16s, tid=0x%x[%d,%d], dir=%d, ...)",
  292.             RelationGetRelationName(relation), tid, tid->blockData,
  293.             tid->positionData, dir);
  294.     } else {
  295.         elog(DEBUG, "heapgettup(%.16s, tid=0x%x, dir=%d, ...)",
  296.             RelationGetRelationName(relation), tid, dir);
  297.     }
  298.     elog(DEBUG, "heapgettup(..., b=0x%x, timeQ=0x%x, nkeys=%d, key=0x%x",
  299.         b, timeQual, nkeys, key);
  300.     if (timeQual == SelfTimeQual) {
  301.         elog(DEBUG, "heapgettup: relation(%c)=`%.16s', SelfTimeQual",
  302.             relation->rd_rel->relkind, &relation->rd_rel->relname);
  303.     } else {
  304.         elog(DEBUG, "heapgettup: relation(%c)=`%.16s', timeQual=%d",
  305.             relation->rd_rel->relkind, &relation->rd_rel->relname,
  306.             timeQual);
  307.     }
  308. #endif    /* !defined(HEAPDEBUGALL) */
  309.  
  310.     if (!ItemPointerIsValid(tid)) {
  311.     Assert(!PointerIsValid(tid));
  312.     }
  313.  
  314.     /* ----------------
  315.      *    return null immediately if relation is empty
  316.      * ----------------
  317.      */
  318.      if (!(pages = relation->rd_nblocks))
  319.     return (NULL);
  320.  
  321.     /* ----------------
  322.      *    calculate next starting lineoff, given scan direction
  323.      * ----------------
  324.      */
  325.     if (!dir) {
  326.     /* ----------------
  327.      * ``no movement'' scan direction
  328.      * ----------------
  329.      */
  330.     /* assume it is a valid TID XXX    */
  331.     if (ItemPointerIsValid(tid) == false) {
  332.         *b = InvalidBuffer;
  333.         return (NULL);
  334.     }
  335.     *b = RelationGetBufferWithBuffer(relation,
  336.                              ItemPointerGetBlockNumber(tid),
  337.                              *b);
  338.     
  339. #ifndef NO_BUFFERISVALID
  340.     if (!BufferIsValid(*b)) {
  341.         elog(WARN, "heapgettup: failed ReadBuffer");
  342.     }
  343. #endif
  344.     
  345.     dp = (Page) BufferSimpleGetPage(*b);
  346.     offsetIndex = ItemPointerSimpleGetOffsetIndex(tid);
  347.     lpp = PageGetItemId(dp, offsetIndex);
  348.  
  349.     Assert(!ItemIdIsLock(lpp));
  350.  
  351.     rtup = (HeapTuple)PageGetItem((Page) dp, lpp);
  352.     return (rtup);
  353.     
  354.     } else if (dir < 0) {
  355.     /* ----------------
  356.      *  reverse scan direction
  357.      * ----------------
  358.      */
  359.     if (ItemPointerIsValid(tid) == false) {
  360.         tid = NULL;
  361.     }
  362.     page = (tid == NULL) ?
  363.         pages - 1 - initskip(parallel_ok) : ItemPointerGetBlockNumber(tid);
  364.  
  365.     if (page < 0) {    
  366.         *b = InvalidBuffer;
  367.         return (NULL);
  368.     }
  369.  
  370.     *b = RelationGetBufferWithBuffer(relation, page, *b);
  371. #ifndef NO_BUFFERISVALID
  372.     if (!BufferIsValid(*b)) {
  373.         elog(WARN, "heapgettup: failed ReadBuffer");
  374.     }
  375. #endif
  376.     
  377.     dp = (Page) BufferSimpleGetPage(*b);
  378.     lines = 1 + PageGetMaxOffsetIndex(dp);
  379.     lineoff = (tid == NULL) ?
  380.         lines - 1 : ItemPointerSimpleGetOffsetIndex(tid) - 1;
  381.     /* page and lineoff now reference the physically previous tid */
  382.  
  383.     } else {
  384.     /* ----------------
  385.      *  forward scan direction
  386.      * ----------------
  387.      */
  388.     if (ItemPointerIsValid(tid) == false) {
  389.         page = initskip(parallel_ok);
  390.         lineoff = 0;
  391.     } else {
  392.         page = ItemPointerGetBlockNumber(tid);
  393.         lineoff = 1 + ItemPointerSimpleGetOffsetIndex(tid);
  394.     }
  395.  
  396.     if (page >= pages) {
  397.         *b = InvalidBuffer;
  398.         return (NULL);
  399.     }
  400.  
  401.     /* page and lineoff now reference the physically next tid */
  402.     *b = RelationGetBufferWithBuffer(relation, page, *b);
  403.     
  404. #ifndef NO_BUFFERISVALID
  405.     if (!BufferIsValid(*b)) {
  406.         elog(WARN, "heapgettup: failed ReadBuffer");
  407.     }
  408. #endif
  409.     
  410.     dp = (Page) BufferSimpleGetPage(*b);
  411.     lines = 1 + PageGetMaxOffsetIndex(dp);
  412.     }
  413.  
  414.     /* ----------------
  415.      *    calculate line pointer and number of remaining items
  416.      *  to check on this page.
  417.      *
  418.      *  hack hack hack:
  419.      *  lineoff becomes the number of additional lines left to check
  420.      * ----------------
  421.      */
  422.     lpp = PageGetItemId(dp, lineoff);
  423.     lineoff = (dir < 0) ? lineoff : lines - lineoff - 1;
  424.  
  425.     /* ----------------
  426.      *    advance the scan until we find a qualifying tuple or
  427.      *  run out of stuff to scan
  428.      * ----------------
  429.      */
  430.     for (;;) {
  431.     while (lineoff >= 0) {
  432.         /* ----------------
  433.          *    if current tuple qualifies, return it.
  434.          * ----------------
  435.          */
  436.         if ((rtup = heap_tuple_satisfies(lpp, relation, (PageHeader) dp,
  437.                          timeQual, nkeys, key)) != NULL) {
  438.  
  439.         return (rtup);
  440.         }
  441.  
  442.         /* ----------------
  443.          *    otherwise move to the next item on the page
  444.          * ----------------
  445.          */
  446.         lineoff--;
  447.         (dir < 0) ? lpp-- : lpp++;
  448.     }
  449.  
  450.     /* ----------------
  451.      *  if we get here, it means we've exhausted the items on
  452.      *  this page and it's time to move to the next..
  453.      * ----------------
  454.      */
  455.  
  456.     page = nextpage(page, dir, parallel_ok);
  457.  
  458.     /* ----------------
  459.      *  return NULL if we've exhausted all the pages..
  460.      * ----------------
  461.      */
  462.     if (page < 0 || page >= pages) {
  463.         if (BufferIsValid(*b))
  464.         ReleaseBuffer(*b);
  465.         *b = InvalidBuffer;
  466.         return (NULL);
  467.     }
  468.  
  469.     *b = ReleaseAndReadBuffer(*b, relation, page);
  470.     
  471. #ifndef NO_BUFFERISVALID
  472.     if (!BufferIsValid(*b)) {
  473.         elog(WARN, "heapgettup: failed ReadBuffer");
  474.     }
  475. #endif
  476.     dp = (Page) BufferSimpleGetPage(*b);
  477.     lines = 1 + PageGetMaxOffsetIndex((Page) dp);
  478.     lineoff = lines - 1;
  479.     if (dir < 0) {
  480.         lpp = PageGetItemId(dp, lineoff);
  481.     } else if (dir > 0) {
  482.         lpp = PageGetFirstItemId(dp);
  483.     }
  484.     }
  485. }
  486.  
  487. /* ----------------
  488.  *    doinsert
  489.  *
  490.  *    routine used by heap_insert() which in turn calls
  491.  *    RelationPutHeapTuple() or RelationPutLongHeapTuple().
  492.  * ----------------
  493.  */
  494. RuleLock
  495. doinsert_old(relation, tup)
  496.     Relation    relation;
  497.     HeapTuple    tup;
  498. {
  499.     Buffer        b;
  500.     PageHeader        dp;
  501.     int            pages;
  502.     BlockIndexList    list;
  503.     Index        index;
  504.     BlockNumber        blockIndex;
  505.  
  506.     /* ----------------
  507.      *    ??? -cim
  508.      * ----------------
  509.      */
  510.     ItemPointerSetInvalid(&tup->t_chain);
  511.  
  512.     /* ----------------
  513.      *    ??? -cim
  514.      * ----------------
  515.      */
  516.     if (tup->t_len > MAXTUPLEN ||
  517.     !(pages = RelationGetNumberOfBlocks(relation))) {
  518.     RelationPutLongHeapTuple(relation, tup);    /* ??? */
  519.     return ((RuleLock)NULL);
  520.     }
  521.  
  522.     /* ----------------
  523.      *    compute proper location if cluster--passed as argument?
  524.      * ----------------
  525.      */
  526.     blockIndex = pages - 1;
  527.     
  528. #ifdef    DOCLUSTER
  529.     blockIndex = getclusterblockindex();
  530. #endif  DOCLUSTER
  531.  
  532.     /* ----------------
  533.      *    ??? -cim
  534.      * ----------------
  535.      */
  536.     if (BlockNumberIsValid(blockIndex)) {
  537.     if (RelationContainsUsableBlock(relation,
  538.                     blockIndex,
  539.                     tup->t_len,
  540.                     ClusteredNumberOfFailures)) {
  541.             
  542. #ifdef    RANDOMDEBUG
  543.         elog(DEBUG, "clustered@%d", blockIndex);
  544. #endif    RANDOMDEBUG
  545.     } else {
  546.         blockIndex = InvalidBlockNumber;
  547.     }
  548.     }
  549.  
  550.     /* ----------------
  551.      *    ??? -cim
  552.      * ----------------
  553.      */
  554. #ifdef    DOCLUSTER
  555.     if (!BlockNumberIsValid(blockIndex)) {
  556.     list = RelationGetRandomBlockIndexList(relation, tup->t_oid);
  557.     for (index = 0; BlockNumberIsValid(list[index]); index += 1) {
  558.         if (RelationContainsUsableBlock(relation,
  559.                         list[index],
  560.                         tup->t_len,
  561.                         index)) {
  562.         blockIndex = list[index];
  563.         
  564. #ifdef    RANDOMDEBUG
  565.         elog(DEBUG, "append@%d", blockIndex);
  566. #endif    RANDOMDEBUG
  567.         break;
  568.         }
  569.     }
  570.     }
  571. #endif
  572.  
  573.     /* ----------------
  574.      *    ??? -cim
  575.      * ----------------
  576.      */
  577.     
  578.     if (BlockNumberIsValid(blockIndex)) {
  579.     /* ----------------
  580.      *    we've finally found a block with space
  581.      *    for our tuple, so insert it there.
  582.      * ----------------
  583.      */
  584.     RelationPutHeapTuple(relation, blockIndex, tup);
  585.     setclusterblockindex(blockIndex);
  586.     }
  587. #ifdef    DOCLUSTER
  588.     else if (BlockNumberIsValid(list[0])) {
  589.     /* ----------------
  590.      *    ??? -cim
  591.      * ----------------
  592.      */
  593.     RelationPutLongHeapTuple(relation, tup);
  594.     setclusterblockindex(pages);    /* XXX PutLong assumption */
  595.     }
  596. #endif
  597.     else {
  598.     /* ----------------
  599.      *    ??? -cim
  600.      * ----------------
  601.      */
  602.     b = ReadBuffer(relation, pages - 1);
  603. #ifndef NO_BUFFERISVALID
  604.     if (!BufferIsValid(b)) {
  605.         /* XXX L_SH better ??? */
  606.         elog(WARN, "aminsert: failed ReadBuffer");
  607.     }
  608. #endif
  609.     
  610.     dp = (PageHeader)BufferSimpleGetPage(b);
  611.     if ((int)tup->t_len > PageGetFreeSpace((Page) dp)) {
  612.         ReleaseBuffer(b);
  613.         /* XXX there is a window in which the status can change */
  614.         RelationPutLongHeapTuple(relation, tup);
  615.     } else {
  616.         ReleaseBuffer(b);
  617.         /* XXX there is a window in which the status can change */
  618.         RelationPutHeapTuple(relation, pages - 1, tup);
  619.     }
  620.     }
  621.     return ((RuleLock)NULL);
  622. }
  623.  
  624. RuleLock
  625. doinsert(relation, tup)
  626.  
  627. Relation relation;
  628. HeapTuple tup;
  629.  
  630. {
  631.     RelationPutHeapTupleAtEnd(relation, tup);
  632.     return(NULL);
  633. }
  634.  
  635. /* 
  636.  *    HeapScanIsValid is now a macro in relscan.h -cim 4/27/91
  637.  */
  638.  
  639. /* ----------------
  640.  *    SetHeapAccessMethodImmediateInvalidation
  641.  * ----------------
  642.  */
  643. void
  644. SetHeapAccessMethodImmediateInvalidation(on)
  645.     bool    on;
  646. {
  647.     ImmediateInvalidation = on;
  648. }
  649.  
  650. /* ----------------------------------------------------------------
  651.  *                   heap access method interface
  652.  * ----------------------------------------------------------------
  653.  */
  654. /* ----------------
  655.  *    heap_open - open a heap relation by relationId
  656.  *
  657.  *    presently the relcache routines do all the work we need
  658.  *    to open/close heap relations.
  659.  * ----------------
  660.  */
  661. Relation
  662. heap_open(relationId)
  663.     ObjectId    relationId;
  664. {
  665.     Relation r;
  666.  
  667.     /* ----------------
  668.      *    increment access statistics
  669.      * ----------------
  670.      */
  671.     IncrHeapAccessStat(local_open);
  672.     IncrHeapAccessStat(global_open);
  673.     
  674.     r = (Relation) RelationIdGetRelation(relationId);
  675.  
  676.     if (RelationIsValid(r) && r->rd_rel->relkind == 'i') {
  677.     elog(WARN, "%.16s is an index relation",
  678.          &(r->rd_rel->relname.data[0]));
  679.     }
  680.  
  681.     return (r);
  682. }
  683.  
  684. /* ----------------
  685.  *    heap_openr - open a heap relation by name
  686.  *
  687.  *    presently the relcache routines do all the work we need
  688.  *    to open/close heap relations.
  689.  * ----------------
  690.  */
  691. Relation
  692. heap_openr(relationName)
  693.     Name relationName;
  694. {
  695.     Relation r;
  696.  
  697.     /* ----------------
  698.      *    increment access statistics
  699.      * ----------------
  700.      */
  701.     IncrHeapAccessStat(local_openr);
  702.     IncrHeapAccessStat(global_openr);
  703.     
  704.     r = (Relation) RelationNameGetRelation(relationName);
  705.  
  706.     if (RelationIsValid(r) && r->rd_rel->relkind == 'i') {
  707.     elog(WARN, "%.16s is an index relation",
  708.          &(r->rd_rel->relname.data[0]));
  709.     }
  710.  
  711.     return (r);
  712. }
  713.  
  714. /* ----------------
  715.  *    heap_close - close a heap relation
  716.  *
  717.  *    presently the relcache routines do all the work we need
  718.  *    to open/close heap relations.
  719.  * ----------------
  720.  */
  721. void
  722. heap_close(relation)
  723.     Relation relation;
  724. {
  725.     /* ----------------
  726.      *    increment access statistics
  727.      * ----------------
  728.      */
  729.     IncrHeapAccessStat(local_close);
  730.     IncrHeapAccessStat(global_close);
  731.     
  732.     (void) RelationClose(relation);
  733. }
  734.  
  735.     
  736. /* ----------------
  737.  *    heap_beginscan    - begin relation scan
  738.  * ----------------
  739.  */
  740.  
  741. HeapScanDesc
  742. heap_beginscan(relation, atend, timeQual, nkeys, key)
  743.     Relation    relation;
  744.     int        atend;
  745.     TimeQual    timeQual;
  746.     unsigned    nkeys;
  747.     ScanKey        key;
  748. {
  749.     HeapScanDesc    sdesc;
  750.  
  751.     /* ----------------
  752.      *    increment access statistics
  753.      * ----------------
  754.      */
  755.     IncrHeapAccessStat(local_beginscan);
  756.     IncrHeapAccessStat(global_beginscan);
  757.  
  758.     /* ----------------
  759.      *    sanity checks
  760.      * ----------------
  761.      */
  762.     if (RelationIsValid(relation) == false)
  763.     elog(WARN, "heap_beginscan: !RelationIsValid(relation)");
  764.     
  765.     /* ----------------
  766.      * set relation level read lock
  767.      * ----------------
  768.      */
  769.     RelationSetLockForRead(relation);
  770.  
  771.     /* XXX someday assert SelfTimeQual if relkind == 'u' */
  772.     if (relation->rd_rel->relkind == 'u') {
  773.     timeQual = SelfTimeQual;
  774.     }
  775.  
  776.     /* ----------------
  777.      *  increment relation ref count while scanning relation
  778.      * ----------------
  779.      */
  780.     RelationIncrementReferenceCount(relation);
  781.     
  782.     /* ----------------
  783.      *    allocate and initialize scan descriptor
  784.      * ----------------
  785.      */
  786.     sdesc = (HeapScanDesc)
  787.     palloc(sizeof *sdesc + (nkeys - 1) * sizeof key->data); /* XXX */
  788.  
  789.     relation->rd_nblocks = smgrnblocks(relation->rd_rel->relsmgr, relation);
  790.     sdesc->rs_rd = relation;
  791.  
  792.     initsdesc(sdesc, relation, atend, nkeys, key);
  793.     
  794.     sdesc->rs_atend = atend;
  795.     sdesc->rs_tr = timeQual;
  796.     sdesc->rs_nkeys = (short)nkeys;
  797.  
  798.     sdesc->rs_parallel_ok = false;
  799.     
  800.     return (sdesc);
  801. }
  802.  
  803. /* ----------------
  804.  *    heap_rescan    - restart a relation scan
  805.  * ----------------
  806.  */
  807. void
  808. heap_rescan(sdesc, scanFromEnd, key)
  809.     HeapScanDesc    sdesc;
  810.     bool        scanFromEnd;
  811.     ScanKey        key;
  812. {
  813.     /* ----------------
  814.      *    increment access statistics
  815.      * ----------------
  816.      */
  817.     IncrHeapAccessStat(local_rescan);
  818.     IncrHeapAccessStat(global_rescan);
  819.     
  820.     /* Note: set relation level read lock is still set */
  821.  
  822.     /* ----------------
  823.      *    unpin scan buffers
  824.      * ----------------
  825.      */
  826.     unpinsdesc(sdesc);
  827.     
  828.     /* ----------------
  829.      *    reinitialize scan descriptor
  830.      * ----------------
  831.      */
  832.     initsdesc(sdesc, sdesc->rs_rd, scanFromEnd, sdesc->rs_nkeys, key);
  833.     sdesc->rs_atend = (Boolean) scanFromEnd;
  834. }
  835.  
  836. /* ----------------
  837.  *    heap_endscan    - end relation scan
  838.  *
  839.  *    See how to integrate with index scans.
  840.  *    Check handling if reldesc caching.
  841.  * ----------------
  842.  */
  843. void
  844. heap_endscan(sdesc)
  845.     HeapScanDesc    sdesc;
  846. {
  847.     /* ----------------
  848.      *    increment access statistics
  849.      * ----------------
  850.      */
  851.     IncrHeapAccessStat(local_endscan);    
  852.     IncrHeapAccessStat(global_endscan);    
  853.     
  854.     /* Note: no locking manipulations needed */
  855.  
  856.     /* ----------------
  857.      *    unpin scan buffers
  858.      * ----------------
  859.      */
  860.     unpinsdesc(sdesc);
  861.     
  862.     /* ----------------
  863.      *    decrement relation reference count and free scan descriptor storage
  864.      * ----------------
  865.      */
  866.     RelationDecrementReferenceCount(sdesc->rs_rd);
  867.  
  868.     /* ----------------
  869.      * Non 2-phase read locks on catalog relations
  870.      * ----------------
  871.      */
  872.     if ( issystem(RelationGetRelationName(sdesc->rs_rd)) )
  873.     RelationUnsetLockForRead(sdesc->rs_rd);
  874.  
  875.     pfree((char *)sdesc);    /* XXX */
  876. }
  877.  
  878. /* ----------------
  879.  *    heap_getnext    - retrieve next tuple in scan
  880.  *
  881.  *    Fix to work with index relations.
  882.  * ----------------
  883.  */
  884.  
  885. #ifdef HEAPDEBUGALL
  886. #define HEAPDEBUG_1 \
  887.    elog(DEBUG, "heap_getnext([%.16s,nkeys=%d],backw=%d,0x%x) called", \
  888.     &sdesc->rs_rd->rd_rel->relname, sdesc->rs_nkeys, backw, b)
  889.  
  890. #define HEAPDEBUG_2 \
  891.    elog(DEBUG, "heap_getnext called with backw (no tracing yet)")
  892.  
  893. #define HEAPDEBUG_3 \
  894.    elog(DEBUG, "heap_getnext returns NULL at end")
  895.  
  896. #define HEAPDEBUG_4 \
  897.    elog(DEBUG, "heap_getnext valid buffer UNPIN'd")
  898.  
  899. #define HEAPDEBUG_5 \
  900.    elog(DEBUG, "heap_getnext next tuple was cached")
  901.  
  902. #define HEAPDEBUG_6 \
  903.    elog(DEBUG, "heap_getnext returning EOS")
  904.  
  905. #define HEAPDEBUG_7 \
  906.    elog(DEBUG, "heap_getnext returning tuple");
  907. #else
  908. #define HEAPDEBUG_1
  909. #define HEAPDEBUG_2
  910. #define HEAPDEBUG_3
  911. #define HEAPDEBUG_4
  912. #define HEAPDEBUG_5
  913. #define HEAPDEBUG_6
  914. #define HEAPDEBUG_7
  915. #endif    /* !defined(HEAPDEBUGALL) */
  916.  
  917.  
  918. HeapTuple
  919. heap_getnext(scandesc, backw, b)
  920.     HeapScanDesc    scandesc;
  921.     int            backw;
  922.     Buffer        *b;
  923. {
  924.     register HeapScanDesc sdesc = scandesc;
  925.     Buffer          localb;
  926.  
  927.     /* ----------------
  928.      *    increment access statistics
  929.      * ----------------
  930.      */
  931.     IncrHeapAccessStat(local_getnext);    
  932.     IncrHeapAccessStat(global_getnext);    
  933.  
  934.     /* Note: no locking manipulations needed */
  935.  
  936.     /* ----------------
  937.      *    argument checks
  938.      * ----------------
  939.      */
  940.     if (sdesc == NULL)
  941.     elog(WARN, "heap_getnext: NULL relscan");
  942.  
  943.     /* ----------------
  944.      *    initialize return buffer to InvalidBuffer
  945.      * ----------------
  946.      */
  947.     if (! PointerIsValid(b)) b = &localb;
  948.     (*b) = InvalidBuffer;
  949.     
  950.     HEAPDEBUG_1; /* heap_getnext( info ) */
  951.     
  952.     if (backw) {
  953.     /* ----------------
  954.      *  handle reverse scan
  955.      * ----------------
  956.      */
  957.     HEAPDEBUG_2; /* heap_getnext called with backw */
  958.     
  959.     if (sdesc->rs_ptup == sdesc->rs_ctup &&
  960.         BufferIsInvalid(sdesc->rs_pbuf))
  961.         {
  962.         if (BufferIsValid(sdesc->rs_nbuf))
  963.             ReleaseBuffer(sdesc->rs_nbuf);
  964.         return (NULL);
  965.         }
  966.  
  967.     /*
  968.      * Copy the "current" tuple/buffer
  969.      * to "next". Pin/unpin the buffers
  970.      * accordingly
  971.      */
  972.     if (sdesc->rs_nbuf != sdesc->rs_cbuf) {
  973.         if (BufferIsValid(sdesc->rs_nbuf))
  974.         ReleaseBuffer(sdesc->rs_nbuf);
  975.         if (BufferIsValid(sdesc->rs_cbuf))
  976.         IncrBufferRefCount(sdesc->rs_cbuf);
  977.     }
  978.     sdesc->rs_ntup = sdesc->rs_ctup;
  979.     sdesc->rs_nbuf = sdesc->rs_cbuf;
  980.  
  981.     if (sdesc->rs_ptup != NULL) {
  982.         if (sdesc->rs_cbuf != sdesc->rs_pbuf) {
  983.         if (BufferIsValid(sdesc->rs_cbuf))
  984.             ReleaseBuffer(sdesc->rs_cbuf);
  985.         if (BufferIsValid(sdesc->rs_pbuf))
  986.             IncrBufferRefCount(sdesc->rs_pbuf);
  987.         }
  988.         sdesc->rs_ctup = sdesc->rs_ptup;
  989.         sdesc->rs_cbuf = sdesc->rs_pbuf;
  990.     } else { /* NONTUP */
  991.         ItemPointer iptr;
  992.  
  993.         iptr = (sdesc->rs_ctup != NULL) ?
  994.         &(sdesc->rs_ctup->t_ctid) : (ItemPointer) NULL;
  995.         
  996.         if (BufferIsValid(sdesc->rs_cbuf))
  997.         ReleaseBuffer(sdesc->rs_cbuf);
  998.         sdesc->rs_ctup = (HeapTuple)
  999.         heapgettup(sdesc->rs_rd,
  1000.                iptr,
  1001.                -1,
  1002.                &(sdesc->rs_cbuf),
  1003.                sdesc->rs_tr,
  1004.                sdesc->rs_nkeys,
  1005.                &(sdesc->rs_key),
  1006.                sdesc->rs_parallel_ok);
  1007.     }
  1008.  
  1009.     if (sdesc->rs_ctup == NULL && !BufferIsValid(sdesc->rs_cbuf))
  1010.         {
  1011.         if (BufferIsValid(sdesc->rs_pbuf))
  1012.             ReleaseBuffer(sdesc->rs_pbuf);
  1013.         sdesc->rs_ptup = NULL;
  1014.         sdesc->rs_pbuf = InvalidBuffer;
  1015.         if (BufferIsValid(sdesc->rs_nbuf))
  1016.             ReleaseBuffer(sdesc->rs_nbuf);
  1017.         sdesc->rs_ntup = NULL;
  1018.         sdesc->rs_nbuf = InvalidBuffer;
  1019.         return (NULL);
  1020.         }
  1021.  
  1022.     if (BufferIsValid(sdesc->rs_pbuf))
  1023.         ReleaseBuffer(sdesc->rs_pbuf);
  1024.     sdesc->rs_ptup = NULL;
  1025.     sdesc->rs_pbuf = UnknownBuffer;
  1026.  
  1027.     } else {
  1028.     /* ----------------
  1029.      *  handle forward scan
  1030.      * ----------------
  1031.      */
  1032.     if (sdesc->rs_ctup == sdesc->rs_ntup &&
  1033.         BufferIsInvalid(sdesc->rs_nbuf)) {
  1034.         if (BufferIsValid(sdesc->rs_pbuf))
  1035.         ReleaseBuffer(sdesc->rs_pbuf);
  1036.         HEAPDEBUG_3; /* heap_getnext returns NULL at end */
  1037.         return (NULL);
  1038.     }
  1039.  
  1040.     /*
  1041.      * Copy the "current" tuple/buffer
  1042.      * to "previous". Pin/unpin the buffers
  1043.      * accordingly
  1044.      */
  1045.     if (sdesc->rs_pbuf != sdesc->rs_cbuf) {
  1046.         if (BufferIsValid(sdesc->rs_pbuf))
  1047.         ReleaseBuffer(sdesc->rs_pbuf);
  1048.         if (BufferIsValid(sdesc->rs_cbuf))
  1049.         IncrBufferRefCount(sdesc->rs_cbuf);
  1050.     }
  1051.     sdesc->rs_ptup = sdesc->rs_ctup;
  1052.     sdesc->rs_pbuf = sdesc->rs_cbuf;
  1053.     
  1054.     if (sdesc->rs_ntup != NULL) {
  1055.         if (sdesc->rs_cbuf != sdesc->rs_nbuf) {
  1056.         if (BufferIsValid(sdesc->rs_cbuf))
  1057.             ReleaseBuffer(sdesc->rs_cbuf);
  1058.         if (BufferIsValid(sdesc->rs_nbuf))
  1059.             IncrBufferRefCount(sdesc->rs_nbuf);
  1060.         }
  1061.         sdesc->rs_ctup = sdesc->rs_ntup;
  1062.         sdesc->rs_cbuf = sdesc->rs_nbuf;
  1063.         HEAPDEBUG_5; /* heap_getnext next tuple was cached */
  1064.     } else { /* NONTUP */
  1065.         ItemPointer iptr;
  1066.  
  1067.         iptr = (sdesc->rs_ctup != NULL) ?
  1068.         &sdesc->rs_ctup->t_ctid : (ItemPointer) NULL;
  1069.         
  1070.         if (BufferIsValid(sdesc->rs_cbuf))
  1071.         ReleaseBuffer(sdesc->rs_cbuf);
  1072.  
  1073.         sdesc->rs_ctup = (HeapTuple)
  1074.         heapgettup(sdesc->rs_rd,
  1075.                iptr,
  1076.                1,
  1077.                &sdesc->rs_cbuf,
  1078.                sdesc->rs_tr,
  1079.                sdesc->rs_nkeys,
  1080.                &sdesc->rs_key,
  1081.                sdesc->rs_parallel_ok);
  1082.     }
  1083.  
  1084.     if (sdesc->rs_ctup == NULL && !BufferIsValid(sdesc->rs_cbuf)) {
  1085.         if (BufferIsValid(sdesc->rs_nbuf))
  1086.         ReleaseBuffer(sdesc->rs_nbuf);
  1087.         sdesc->rs_ntup = NULL;
  1088.         sdesc->rs_nbuf = InvalidBuffer;
  1089.         if (BufferIsValid(sdesc->rs_pbuf))
  1090.         ReleaseBuffer(sdesc->rs_pbuf);
  1091.         sdesc->rs_ptup = NULL;
  1092.         sdesc->rs_pbuf = InvalidBuffer;
  1093.         HEAPDEBUG_6; /* heap_getnext returning EOS */
  1094.         return (NULL);
  1095.     }
  1096.     
  1097.     if (BufferIsValid(sdesc->rs_nbuf))
  1098.         ReleaseBuffer(sdesc->rs_nbuf);
  1099.     sdesc->rs_ntup = NULL;
  1100.     sdesc->rs_nbuf = UnknownBuffer;
  1101.     }
  1102.  
  1103.     /* ----------------
  1104.      *    if we get here it means we have a new current scan tuple, so
  1105.      *  point to the proper return buffer and return the tuple.
  1106.      * ----------------
  1107.      */
  1108.     (*b) = sdesc->rs_cbuf;
  1109.     
  1110.     HEAPDEBUG_7; /* heap_getnext returning tuple */
  1111.     
  1112.     return (sdesc->rs_ctup);
  1113. }
  1114.  
  1115. /* ----------------
  1116.  *    heap_fetch    - retrive tuple with tid
  1117.  *
  1118.  *    Currently ignores LP_IVALID during processing!
  1119.  * ----------------
  1120.  */
  1121. HeapTuple
  1122. heap_fetch(relation, timeQual, tid, b)
  1123.     Relation    relation;
  1124.     TimeQual    timeQual;
  1125.     ItemPointer    tid;
  1126.     Buffer    *b;
  1127. {
  1128.     ItemId    lp;
  1129.     Buffer    buffer;
  1130.     PageHeader    dp;
  1131.     HeapTuple    tuple;
  1132.     OffsetIndex    offsetIndex;
  1133.     HeapTuple    heap_copytuple();
  1134.  
  1135.     /* ----------------
  1136.      *    increment access statistics
  1137.      * ----------------
  1138.      */
  1139.     IncrHeapAccessStat(local_fetch);    
  1140.     IncrHeapAccessStat(global_fetch);    
  1141.  
  1142.     /*
  1143.      * Note: This is collosally expensive - does two system calls per
  1144.      * indexscan tuple fetch.  Not good, and since we should be doing
  1145.      * page level locking by the scanner anyway, it is commented out.
  1146.      */
  1147.  
  1148.     /* RelationSetLockForTupleRead(relation, tid); */
  1149.  
  1150.     /* ----------------
  1151.      *    get the buffer from the relation descriptor
  1152.      *  Note that this does a buffer pin.
  1153.      * ----------------
  1154.      */
  1155.  
  1156.     buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
  1157.     
  1158. #ifndef NO_BUFFERISVALID
  1159.     if (!BufferIsValid(buffer)) {
  1160.     elog(WARN, "heap_fetch: %s relation: ReadBuffer(%lx) failed",
  1161.          &relation->rd_rel->relname, (long)tid);
  1162.     }
  1163. #endif
  1164.  
  1165.     /* ----------------
  1166.      *    get the item line pointer corresponding to the requested tid
  1167.      * ----------------
  1168.      */
  1169.     dp = (PageHeader) BufferSimpleGetPage(buffer);
  1170.     offsetIndex = ItemPointerSimpleGetOffsetIndex(tid);
  1171.     lp = PageGetItemId(dp, offsetIndex);
  1172.  
  1173.     /* ----------------
  1174.      *    more sanity checks
  1175.      * ----------------
  1176.      */
  1177.  
  1178.     Assert(ItemIdIsUsed(lp)); 
  1179.     Assert(!(ItemIdIsContinuation(lp) || ItemIdIsInternal(lp)));
  1180.  
  1181.     /* ----------------
  1182.      *    check time qualification of tid
  1183.      * ----------------
  1184.      */
  1185.  
  1186.     tuple = heap_tuple_satisfies(lp, relation, dp,
  1187.                  timeQual, 0,(ScanKey)NULL);
  1188.  
  1189.     if (tuple == NULL)
  1190.     {
  1191.     ReleaseBuffer(buffer);
  1192.     return (NULL);
  1193.     }
  1194.  
  1195.     /* ----------------
  1196.      *    all checks passed, now either return a copy of the tuple
  1197.      *  or pin the buffer page and return a pointer, depending on
  1198.      *  whether caller gave us a valid b.
  1199.      * ----------------
  1200.      */
  1201.  
  1202.     if (PointerIsValid(b)) {
  1203.     *b = buffer;
  1204.     } else {
  1205.     tuple = heap_copytuple(tuple, buffer, relation);
  1206.     ReleaseBuffer(buffer);
  1207.     }
  1208.     return (tuple);
  1209.  
  1210.     /* Note: lots of commented code was removed from here. */
  1211. }
  1212.  
  1213. /* ----------------
  1214.  *    heap_insert    - insert tuple
  1215.  *
  1216.  *    The assignment of t_min (and thus the others) should be
  1217.  *    removed eventually.
  1218.  *
  1219.  *    Currently places the tuple onto the last page.  If there is no room,
  1220.  *    it is placed on new pages.  (Heap relations)
  1221.  *    Note that concurrent inserts during a scan will probably have
  1222.  *    unexpected results, though this will be fixed eventually.
  1223.  *
  1224.  *    Fix to work with indexes.
  1225.  * ----------------
  1226.  */
  1227.  
  1228. ObjectId
  1229. heap_insert(relation, tup, off)
  1230.     Relation    relation;
  1231.     HeapTuple    tup;
  1232.     double    *off;
  1233. {
  1234.     RuleLock returnMe;
  1235.  
  1236.     /* ----------------
  1237.      *    increment access statistics
  1238.      * ----------------
  1239.      */
  1240.     IncrHeapAccessStat(local_insert);
  1241.     IncrHeapAccessStat(global_insert);
  1242.  
  1243.     /* ----------------
  1244.      *    set relation level read lock
  1245.      * ----------------
  1246.      */
  1247.  
  1248.     RelationSetLockForWrite(relation);
  1249.  
  1250.     if (off != NULL)
  1251.     *off = -1.0;            /* XXX ignore off for now */
  1252.  
  1253.     /* ----------------
  1254.      *  If the object id of this tuple has already been assigned, trust
  1255.      *  the caller.  There are a couple of ways this can happen.  At initial
  1256.      *  db creation, the backend program sets oids for tuples.  When we
  1257.      *  define an index, we set the oid.  Finally, in the future, we may
  1258.      *  allow users to set their own object ids in order to support a
  1259.      *  persistent object store (objects need to contain pointers to one
  1260.      *  another).
  1261.      * ----------------
  1262.      */
  1263.     if (!ObjectIdIsValid(tup->t_oid)) {
  1264.     tup->t_oid = newoid();
  1265.     LastOidProcessed = tup->t_oid;
  1266.     }
  1267.  
  1268.     TransactionIdStore(GetCurrentTransactionId(), &(tup->t_xmin));
  1269.     tup->t_cmin = GetCurrentCommandId();
  1270.     PointerStoreInvalidTransactionId((Pointer)&(tup->t_xmax));
  1271.     tup->t_tmin = InvalidTime;
  1272.     tup->t_tmax = InvalidTime;
  1273.  
  1274.     returnMe = doinsert(relation, tup);
  1275.  
  1276.     if ( issystem(RelationGetRelationName(relation)) )
  1277.     RelationUnsetLockForWrite(relation);
  1278.  
  1279.     /* ----------------
  1280.      *    invalidate caches
  1281.      * ----------------
  1282.      */
  1283.     SetRefreshWhenInvalidate(ImmediateInvalidation);
  1284.     RelationInvalidateHeapTuple(relation, tup);
  1285.     SetRefreshWhenInvalidate((bool)!ImmediateInvalidation);
  1286.  
  1287.     return(tup->t_oid);
  1288. }
  1289.  
  1290. /* ----------------
  1291.  *    heap_delete    - delete a tuple
  1292.  *
  1293.  *    Must decide how to handle errors.
  1294.  * ----------------
  1295.  */
  1296.  
  1297. RuleLock
  1298. heap_delete(relation, tid)
  1299.     Relation    relation;
  1300.     ItemPointer    tid;
  1301. {
  1302.     ItemId        lp;
  1303.     HeapTuple        tp;
  1304.     PageHeader        dp;
  1305.     Buffer        b;
  1306.     long        time();
  1307.     char        *fmgr();
  1308.  
  1309.     /* ----------------
  1310.      *    increment access statistics
  1311.      * ----------------
  1312.      */
  1313.     IncrHeapAccessStat(local_delete);
  1314.     IncrHeapAccessStat(global_delete);
  1315.  
  1316.     /* ----------------
  1317.      *    sanity check
  1318.      * ----------------
  1319.      */
  1320.     Assert(ItemPointerIsValid(tid));
  1321.  
  1322.     /* ----------------
  1323.      *    set relation level write lock
  1324.      * ----------------
  1325.      */
  1326.     RelationSetLockForWrite(relation);
  1327.  
  1328.     b = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
  1329.     
  1330. #ifndef NO_BUFFERISVALID
  1331.     if (!BufferIsValid(b)) { /* XXX L_SH better ??? */
  1332.     elog(WARN, "heap_delete: failed ReadBuffer");
  1333.     }
  1334. #endif NO_BUFFERISVALID
  1335.  
  1336.     dp = (PageHeader) BufferSimpleGetPage(b);
  1337.     lp = PageGetItemId(dp, ItemPointerSimpleGetOffsetIndex(tid));
  1338.  
  1339.     /* ----------------
  1340.      *    check that we're deleteing a valid item
  1341.      * ----------------
  1342.      */
  1343.     if (!(tp = heap_tuple_satisfies(lp, relation, dp,
  1344.                     NowTimeQual, 0, (ScanKey) NULL))) {
  1345.     
  1346.     /* XXX call something else */
  1347.     ReleaseBuffer(b);
  1348.     
  1349.     elog(WARN, "heap_delete: (am)invalid tid");
  1350.     }
  1351.  
  1352.     /* ----------------
  1353.      *    get the tuple and lock tell the buffer manager we want
  1354.      *  exclusive access to the page
  1355.      * ----------------
  1356.      */
  1357.  
  1358.     /* ----------------
  1359.      *    store transaction information of xact deleting the tuple
  1360.      * ----------------
  1361.      */
  1362.     TransactionIdStore(GetCurrentTransactionId(), &(tp->t_xmax));
  1363.     tp->t_cmax = GetCurrentCommandId();
  1364.     ItemPointerSetInvalid(&tp->t_chain);
  1365.  
  1366.     /* ----------------
  1367.      *    invalidate caches
  1368.      * ----------------
  1369.      */
  1370.     SetRefreshWhenInvalidate(ImmediateInvalidation);
  1371.     RelationInvalidateHeapTuple(relation, tp);
  1372.     SetRefreshWhenInvalidate((bool)!ImmediateInvalidation);
  1373.  
  1374.     WriteBuffer(b);
  1375.     if ( issystem(RelationGetRelationName(relation)) )
  1376.     RelationUnsetLockForWrite(relation);
  1377. }
  1378.  
  1379. /* ----------------
  1380.  *    heap_replace    - replace a tuple
  1381.  *
  1382.  *    Must decide how to handle errors.
  1383.  *
  1384.  *    Fix arguments, work with indexes.
  1385.  * ----------------
  1386.  */
  1387.  
  1388. RuleLock
  1389. heap_replace(relation, otid, tup)
  1390.     Relation    relation;
  1391.     ItemPointer    otid;
  1392.     HeapTuple    tup;
  1393. {
  1394.     ItemId        lp;
  1395.     HeapTuple        tp;
  1396.     Page        dp;
  1397.     Buffer        buffer;
  1398.     BlockIndexList    list;
  1399.     BlockNumber        blockIndex;
  1400.     Index        index;
  1401.     long        time();        /* know C */
  1402.  
  1403.     /* ----------------
  1404.      *    increment access statistics
  1405.      * ----------------
  1406.      */
  1407.     IncrHeapAccessStat(local_replace);
  1408.     IncrHeapAccessStat(global_replace);
  1409.  
  1410.     /* ----------------
  1411.      *    sanity checks
  1412.      * ----------------
  1413.      */
  1414.     Assert(ItemPointerIsValid(otid));
  1415.  
  1416.     /* ----------------
  1417.      *    set relation level write lock
  1418.      * ----------------
  1419.      */
  1420.     RelationSetLockForWrite(relation);
  1421.  
  1422.     buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(otid));
  1423. #ifndef NO_BUFFERISVALID
  1424.     if (!BufferIsValid(buffer)) {
  1425.     /* XXX L_SH better ??? */
  1426.     elog(WARN, "amreplace: failed ReadBuffer");
  1427.     }    
  1428. #endif NO_BUFFERISVALID
  1429.     
  1430.     dp = (Page) BufferSimpleGetPage(buffer);
  1431.     lp = PageGetItemId(dp, ItemPointerSimpleGetOffsetIndex(otid));
  1432.  
  1433.     /* ----------------
  1434.      *    logically delete old item
  1435.      * ----------------
  1436.      */
  1437.  
  1438.     tp = (HeapTuple) PageGetItem(dp, lp);
  1439.     Assert(HeapTupleIsValid(tp));
  1440.  
  1441.     /* -----------------
  1442.      *  the following test should be able to catch all non-functional
  1443.      *  update attempts and shut out all ghost tuples.
  1444.      *  XXX In the future, Spyros may need to update the rule lock on a tuple
  1445.      *  more than once within the same command and same transaction.
  1446.      *  He will have to introduce a new flag to override the following check.
  1447.      *  -- Wei
  1448.      *
  1449.      * -----------------
  1450.      */
  1451.  
  1452.     if (TupleUpdatedByCurXactAndCmd(tp)) {
  1453.     elog(NOTICE, "Non-functional update, only first update is performed");
  1454.     if ( issystem(RelationGetRelationName(relation)) )
  1455.         RelationUnsetLockForWrite(relation);
  1456.     ReleaseBuffer(buffer);
  1457.         return (RuleLock)NULL;
  1458.     }
  1459.  
  1460.     /* ----------------
  1461.      *    check that we're replacing a valid item -
  1462.      *
  1463.      *  NOTE that this check must follow the non-functional update test
  1464.      *       above as it can happen that we try to 'replace' the same tuple
  1465.      *       twice in a single transaction.  The second time around the
  1466.      *       tuple will fail the NowTimeQual.  We don't want to abort the
  1467.      *       xact, we only want to flag the 'non-functional' NOTICE. -mer
  1468.      * ----------------
  1469.      */
  1470.     if (!heap_tuple_satisfies(lp,
  1471.                   relation,
  1472.                   (PageHeader)dp,
  1473.                   NowTimeQual,
  1474.                   (ScanKeySize)0,
  1475.                   (ScanKey)NULL))
  1476.     {
  1477.     ReleaseBuffer(buffer);
  1478.     elog(WARN, "heap_replace: (am)invalid otid");
  1479.     }
  1480.  
  1481.     /* XXX order problems if not atomic assignment ??? */
  1482.     tup->t_oid = tp->t_oid;
  1483.     TransactionIdStore(GetCurrentTransactionId(), &(tup->t_xmin));
  1484.     tup->t_cmin = GetCurrentCommandId();
  1485.     PointerStoreInvalidTransactionId((Pointer)&(tup->t_xmax));
  1486.     tup->t_tmin = InvalidTime;
  1487.     tup->t_tmax = InvalidTime;
  1488.     ItemPointerSetInvalid(&tup->t_chain);
  1489.  
  1490.     /* ----------------
  1491.      *    insert new item
  1492.      * ----------------
  1493.      */
  1494.     if ((int)tup->t_len <= PageGetFreeSpace((Page) dp)) {
  1495.     RelationPutHeapTuple(relation, BufferGetBlockNumber(buffer), tup);
  1496.     } else {
  1497.     /* ----------------
  1498.      *  new item won't fit on same page as old item, have to look
  1499.      *  for a new place to put it.
  1500.      * ----------------
  1501.      */
  1502.     
  1503. #ifdef RANDOMINSERT
  1504.     list = RelationGetRandomBlockIndexList(relation, tup->t_oid);
  1505.  
  1506.     blockIndex = InvalidBlockNumber;
  1507.     for (index = 0; BlockNumberIsValid(list[index]); index += 1) {
  1508.         if (RelationContainsUsableBlock(relation,
  1509.                         list[index],
  1510.                         tup->t_len,
  1511.                         index)) {
  1512.         blockIndex = list[index];
  1513. #ifdef    RANDOMDEBUG
  1514.         elog(DEBUG, "replace@%d", blockIndex);
  1515. #endif    /* defined(RANDOMDEBUG) */
  1516.         break;
  1517.         }
  1518.     }
  1519.  
  1520.     if (BlockNumberIsValid(blockIndex)) {
  1521.         RelationPutHeapTuple(relation, blockIndex, tup);
  1522.  
  1523.         /* should check if last block is usable   plai 8/9/90 */
  1524.     } else if (blockIndex = RelationGetNumberOfBlocks(relation) - 1,
  1525.            RelationContainsUsableBlock(relation,
  1526.                            blockIndex,
  1527.                            tup->t_len,
  1528.                            index)) {
  1529.         RelationPutHeapTuple(relation, blockIndex, tup);
  1530.     } else {
  1531.         RelationPutLongHeapTuple(relation, tup);
  1532.     }
  1533. #else   /* RANDOMINSERT */
  1534.  
  1535.     /* should check if last block is usable   plai 8/9/90 */
  1536.     if (blockIndex = RelationGetNumberOfBlocks(relation) - 1,
  1537.         RelationContainsUsableBlock(relation, blockIndex, tup->t_len, 0)) {
  1538.         RelationPutHeapTuple(relation, blockIndex, tup);
  1539.     } else {
  1540.         RelationPutLongHeapTuple(relation, tup);
  1541.     }
  1542. #endif  /* RANDOMINSERT */
  1543.     }
  1544.  
  1545.     /* ----------------
  1546.      *    new item in place, now record transaction information
  1547.      * ----------------
  1548.      */
  1549.     TransactionIdStore(GetCurrentTransactionId(), &(tp->t_xmax));
  1550.     tp->t_cmax = GetCurrentCommandId();
  1551.     tp->t_chain = tup->t_ctid;
  1552.  
  1553.     /* ----------------
  1554.      *    invalidate caches
  1555.      * ----------------
  1556.      */
  1557.     SetRefreshWhenInvalidate(ImmediateInvalidation);
  1558.     RelationInvalidateHeapTuple(relation, tp);
  1559.     SetRefreshWhenInvalidate((bool)!ImmediateInvalidation);
  1560.  
  1561.     WriteBuffer(buffer);
  1562.  
  1563.     if ( issystem(RelationGetRelationName(relation)) )
  1564.     RelationUnsetLockForWrite(relation);
  1565.  
  1566.     return ((RuleLock)NULL);    /* XXX */
  1567. }
  1568.  
  1569. /* ----------------
  1570.  *    heap_markpos    - mark scan position
  1571.  *
  1572.  *    Note:
  1573.  *        Should only one mark be maintained per scan at one time.
  1574.  *    Check if this can be done generally--say calls to get the
  1575.  *    next/previous tuple and NEVER pass struct scandesc to the
  1576.  *    user AM's.  Now, the mark is sent to the executor for safekeeping.
  1577.  *    Probably can store this info into a GENERAL scan structure.
  1578.  *
  1579.  *    May be best to change this call to store the marked position
  1580.  *    (up to 2?) in the scan structure itself.
  1581.  *    Fix to use the proper caching structure.
  1582.  * ----------------
  1583.  */
  1584. void
  1585. heap_markpos(sdesc)
  1586.     HeapScanDesc    sdesc;
  1587. {
  1588.  
  1589.     /* ----------------
  1590.      *    increment access statistics
  1591.      * ----------------
  1592.      */
  1593.     IncrHeapAccessStat(local_markpos);
  1594.     IncrHeapAccessStat(global_markpos);
  1595.         
  1596.     /* Note: no locking manipulations needed */
  1597.  
  1598.     if (sdesc->rs_ptup == NULL &&
  1599.     BufferIsUnknown(sdesc->rs_pbuf)) { /* == NONTUP */
  1600.     sdesc->rs_ptup = (HeapTuple)
  1601.         heapgettup(sdesc->rs_rd,
  1602.                (sdesc->rs_ctup == NULL) ?
  1603.                  (ItemPointer)NULL : &sdesc->rs_ctup->t_ctid,
  1604.                -1,
  1605.                &sdesc->rs_pbuf,
  1606.                sdesc->rs_tr,
  1607.                sdesc->rs_nkeys,
  1608.                &sdesc->rs_key,
  1609.                sdesc->rs_parallel_ok);
  1610.     
  1611.     } else if (sdesc->rs_ntup == NULL &&
  1612.            BufferIsUnknown(sdesc->rs_nbuf)) { /* == NONTUP */
  1613.     sdesc->rs_ntup = (HeapTuple)
  1614.         heapgettup(sdesc->rs_rd,
  1615.                (sdesc->rs_ctup == NULL) ?
  1616.                  (ItemPointer)NULL : &sdesc->rs_ctup->t_ctid,
  1617.                1,
  1618.                &sdesc->rs_nbuf,
  1619.                sdesc->rs_tr,
  1620.                sdesc->rs_nkeys,
  1621.                &sdesc->rs_key,
  1622.                sdesc->rs_parallel_ok);
  1623.     }
  1624.  
  1625.     /* ----------------
  1626.      * Should not unpin the buffer pages.  They may still be in use.
  1627.      * ----------------
  1628.      */
  1629.     if (sdesc->rs_ptup != NULL) {
  1630.     sdesc->rs_mptid = sdesc->rs_ptup->t_ctid;
  1631.     } else {
  1632.     ItemPointerSetInvalid(&sdesc->rs_mptid);
  1633.     }
  1634.     if (sdesc->rs_ctup != NULL) {
  1635.     sdesc->rs_mctid = sdesc->rs_ctup->t_ctid;
  1636.     } else {
  1637.     ItemPointerSetInvalid(&sdesc->rs_mctid);
  1638.     }
  1639.     if (sdesc->rs_ntup != NULL) {
  1640.     sdesc->rs_mntid = sdesc->rs_ntup->t_ctid;
  1641.     } else {
  1642.     ItemPointerSetInvalid(&sdesc->rs_mntid);
  1643.     }
  1644. }
  1645.  
  1646. /* ----------------
  1647.  *    heap_restrpos    - restore position to marked location
  1648.  *
  1649.  *    Note:  there are bad side effects here.  If we were past the end
  1650.  *    of a relation when heapmarkpos is called, then if the relation is
  1651.  *    extended via insert, then the next call to heaprestrpos will set
  1652.  *    cause the added tuples to be visible when the scan continues.
  1653.  *    Problems also arise if the TID's are rearranged!!!
  1654.  *
  1655.  * XXX    might be better to do direct access instead of
  1656.  *    using the generality of heapgettup().
  1657.  *
  1658.  * XXX It is very possible that when a scan is restored, that a tuple
  1659.  * XXX which previously qualified may fail for time range purposes, unless
  1660.  * XXX some form of locking exists (ie., portals currently can act funny.
  1661.  * ----------------
  1662.  */
  1663. void
  1664. heap_restrpos(sdesc)
  1665.     HeapScanDesc    sdesc;
  1666. {
  1667.     /* ----------------
  1668.      *    increment access statistics
  1669.      * ----------------
  1670.      */
  1671.     IncrHeapAccessStat(local_restrpos);
  1672.     IncrHeapAccessStat(global_restrpos);
  1673.     
  1674.     /* XXX no amrestrpos checking that ammarkpos called */
  1675.     
  1676.     /* Note: no locking manipulations needed */
  1677.  
  1678.     if (BufferIsValid(sdesc->rs_pbuf)) {
  1679.     ReleaseBuffer(sdesc->rs_pbuf);
  1680.     }
  1681.     if (BufferIsValid(sdesc->rs_cbuf)) {
  1682.     ReleaseBuffer(sdesc->rs_cbuf);
  1683.     }
  1684.     if (BufferIsValid(sdesc->rs_nbuf)) {
  1685.     ReleaseBuffer(sdesc->rs_nbuf);
  1686.     }
  1687.  
  1688.     if (!ItemPointerIsValid(&sdesc->rs_mptid)) {
  1689.     sdesc->rs_ptup = NULL;
  1690.     sdesc->rs_pbuf = InvalidBuffer;
  1691.     } else {
  1692.     sdesc->rs_ptup = (HeapTuple)
  1693.         heapgettup(sdesc->rs_rd,
  1694.                &sdesc->rs_mptid,
  1695.                0,
  1696.                &sdesc->rs_pbuf,
  1697.                NowTimeQual,
  1698.                0,
  1699.                (ScanKey) NULL,
  1700.                sdesc->rs_parallel_ok);
  1701.     }
  1702.  
  1703.     if (!ItemPointerIsValid(&sdesc->rs_mctid)) {
  1704.     sdesc->rs_ctup = NULL;
  1705.     sdesc->rs_cbuf = InvalidBuffer;
  1706.     } else {
  1707.     sdesc->rs_ctup = (HeapTuple)
  1708.         heapgettup(sdesc->rs_rd,
  1709.                &sdesc->rs_mctid,
  1710.                0,
  1711.                &sdesc->rs_cbuf,
  1712.                NowTimeQual,
  1713.                0,
  1714.                (ScanKey) NULL,
  1715.                sdesc->rs_parallel_ok);
  1716.     }
  1717.  
  1718.     if (!ItemPointerIsValid(&sdesc->rs_mntid)) {
  1719.     sdesc->rs_ntup = NULL;
  1720.     sdesc->rs_nbuf = InvalidBuffer;
  1721.     } else {
  1722.     sdesc->rs_ntup = (HeapTuple)
  1723.         heapgettup(sdesc->rs_rd,
  1724.                &sdesc->rs_mntid,
  1725.                0,
  1726.                &sdesc->rs_nbuf,
  1727.                NowTimeQual,
  1728.                0,
  1729.                (ScanKey) NULL,
  1730.                sdesc->rs_parallel_ok);
  1731.     }
  1732. }
  1733.